﻿using System;
using System.Media;
using System.Windows.Controls;
using System.Windows.Input;

namespace HmmmIDE.Debug
{
    public class Terminal : TextBox
    {

        private bool _isSystemBeepEnabled = true;
        private volatile int _lastPomptIndex = 0;

        public Terminal()
            : base()
        {
            base.IsReadOnly = true; // disable input
            // hook events
            DebugService.InputRequested += OnInputRequested;
            DebugService.OutputRequested += OnOutputRequested;
            
        }


        protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e)
        {

            // If input is not allowed, warn the user and discard its input.
            if (base.IsReadOnly)
            {
                if (_isSystemBeepEnabled) SystemSounds.Beep.Play();
                e.Handled = true;
                return;
            }

            if (CaretIndex < _lastPomptIndex)
            {
                if (_isSystemBeepEnabled)
                    SystemSounds.Beep.Play();
                CaretIndex = Text.Length;
                e.Handled = false;
                if (e.Key == Key.Back || e.Key == Key.Delete)
                    e.Handled = true;
            }
            else if (CaretIndex == _lastPomptIndex && e.Key == Key.Back)
            {
                if (_isSystemBeepEnabled)
                    SystemSounds.Beep.Play();
                e.Handled = true;
            }
            else if (CaretIndex == _lastPomptIndex && e.Key == Key.Left)
            {
                if (_isSystemBeepEnabled)
                    SystemSounds.Beep.Play();
                e.Handled = true;
            }

            if (!e.Handled)
            {
                if (e.Key == Key.Enter)
                {
                    HandleEnterKey();
                    e.Handled = true;
                }
            }

            base.OnPreviewKeyDown(e);
        }

        /// <summary>
        /// Un-subscribe hooked static event
        /// </summary>
        public void Close()
        {
            DebugService.InputRequested -= OnInputRequested;
            DebugService.OutputRequested -= OnOutputRequested;
        }

        private void Write(string text)
        {
            int oldPromptIndex = _lastPomptIndex;
            String insertedText = text + (text.EndsWith("\n") ? "" : "\n");
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                Text += insertedText;
                CaretIndex = Text.Length;
                _lastPomptIndex = oldPromptIndex + insertedText.Length;
                this.Focus();
            }));
        }
        public void OnInputRequested(object sender, EventArgs e)
        {
            this.Write("Please Enter The Number");
            ChangeReadOnly(false);
        }


        private void ChangeReadOnly(bool isreadonly)
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                base.IsReadOnly = isreadonly;
            }));
        }

        protected virtual void HandleEnterKey()
        {
            string line = Text.Substring(_lastPomptIndex);
            Text += "\n";
            ChangeReadOnly(true);
            _lastPomptIndex += line.Length + 1;

            short result = 0;
            if(short.TryParse(line, out result))
            {
                DebugService.IOValue = line;
                DebugService._WaitForEnter.Set();
            }
            else
            {
                Write("\nWrong Input, Please Try Again");
                OnInputRequested(typeof(Terminal), EventArgs.Empty);
            }
        }


        public void OnOutputRequested(object sender, DebugService.TerminalEventArgs e)
        {
            Write("Output: " + e.Value);
        }

    }
}
